/*******************************************************************************
 * UserServiceDelegator.java
 *
 * Created by Nishan
 * Last modified Date: Oct 8, 2008 10:06:37 AM by nishan
 * Version : 0.1
 * Copyright (c) 2008 - 2009 cyberThink Infotech Pvt. Ltd., All rights reserved.
 ******************************************************************************/

package com.printeverywhere.delegator;

import static com.printeverywhere.util.AttributeConstants.CLOSING_SESSION;
import static com.printeverywhere.util.AttributeConstants.GETUSERNOTSTARTWITHALBHA;
import static com.printeverywhere.util.AttributeConstants.ID;
import static com.printeverywhere.util.LoggerConstants.CASEINSENSITIVEUSERLIST;
import static com.printeverywhere.util.LoggerConstants.GETUSERLISTSTARTSWITHDIGITEXCEPTION;
import static com.printeverywhere.util.LoggerConstants.USERACCOUNTSCOUNT;
import static com.printeverywhere.util.LoggerConstants.USERLISTEXCEPTION;
import static com.printeverywhere.util.LoggerConstants.USERLISTSEARCHCRITERIA;
import static com.printeverywhere.util.LoggerConstants.USERLISTSEARCHCRITERIAEXCEPTION;
import static com.printeverywhere.util.LoggerConstants.USERLISTSTARTSWITHDIGIT;

import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.apache.log4j.Logger;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import com.printeverywhere.dto.DateFormat;
import com.printeverywhere.dto.NumberFormat;
import com.printeverywhere.dto.Timezones;
import com.printeverywhere.dto.User;
import com.printeverywhere.dto.UserDateCount;
import com.printeverywhere.util.AttributeConstants;
import com.printeverywhere.util.DateUtil;
import com.printeverywhere.util.HibernateUtil;
import com.printeverywhere.util.SearchCriteria;

/**
 * The Class UserServiceDelegator.
 */
public class UserServiceDelegator {

	/** The log. */
	private static Logger log = Logger.getLogger(UserServiceDelegator.class);

	/**
	 * Gets the list.
	 *
	 * @return the list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	@SuppressWarnings("unchecked")
	public static List<User> getList() throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Getting list for user without search criteria".intern());
		}
		Session session = HibernateUtil.getSession();
		try {
			Transaction transaction = session.beginTransaction();
			List<User> list = session.createCriteria(User.class).list();
			transaction.commit();
			return list;
		} catch (HibernateException e) {
			log
					.error("Got exception when getting list for user without search criteria"
							.intern());
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Gets the number format list.
	 *
	 * @return the number format list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<NumberFormat> getNumberFormatList()
			throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Getting list for NumberFormat without search criteria"
					.intern());
		}
		Session session = HibernateUtil.getSession();
		try {
			Transaction transaction = session.beginTransaction();
			List<NumberFormat> list = session
					.createCriteria(NumberFormat.class).list();
			transaction.commit();
			return list;
		} catch (HibernateException e) {
			log
					.error("Got exception when getting list for NumberFormat without search criteria"
							.intern());
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Gets the date format list.
	 *
	 * @return the date format list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<DateFormat> getDateFormatList()
			throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Getting list for NumberFormat without search criteria"
					.intern());
		}
		Session session = HibernateUtil.getSession();
		try {
			Transaction transaction = session.beginTransaction();
			List<DateFormat> list = session.createCriteria(DateFormat.class)
					.list();
			transaction.commit();
			return list;
		} catch (HibernateException e) {
			log
					.error("Got exception when getting list for NumberFormat without search criteria"
							.intern());
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Gets the timezone list.
	 *
	 * @return the timezone list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<Timezones> getTimezoneList() throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Getting list for Timezones without search criteria"
					.intern());
		}
		Session session = HibernateUtil.getSession();
		try {
			Transaction transaction = session.beginTransaction();
			List<Timezones> list = session.createCriteria(Timezones.class)
					.list();
			transaction.commit();
			return list;
		} catch (HibernateException e) {
			log
					.error("Got exception when getting list for Timezones without search criteria"
							.intern());
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Gets the list.
	 *
	 * @param searchCriteria
	 *            the search criteria
	 *
	 * @return the list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<User> getList(SearchCriteria searchCriteria)
			throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Getting list for user with search criteria".intern());
		}
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		criteria.createAlias("state", "state");
		String orderBY = searchCriteria.getOrderBy();
		if (orderBY != null) {
			if (searchCriteria.isAsc()) {
				criteria.addOrder(Order.asc(orderBY));
			} else {
				criteria.addOrder(Order.desc(orderBY));
			}
		}
		Set<String> keys = searchCriteria.getAttributeNames();
		Iterator<String> it = keys.iterator();
		String key = null;
		Object value = null;
		while (it.hasNext()) {
			key = it.next();
			value = searchCriteria.getAttribute(key);

			criteria.add(Restrictions.eq(key, value));
		}
		Transaction transaction = session.beginTransaction();
		List<User> list;
		try {
			list = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log
					.error("Got exception when getting list for user with search criteria"
							.intern());
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return list;
	}

	/**
	 * Gets the user list starts with digit.
	 *
	 * @return the user list starts with digit
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<User> getUserListStartsWithDigit()
			throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSTARTSWITHDIGIT);
		}
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();
		List<User> list;
		try {
			list = session.getNamedQuery(GETUSERNOTSTARTWITHALBHA).list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(GETUSERLISTSTARTSWITHDIGITEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return list;
	}

	/**
	 * Gets the case insensitive list.
	 *
	 * @param searchCriteria
	 *            the search criteria
	 *
	 * @return the case insensitive list
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<User> getCaseInsensitiveList(
			SearchCriteria searchCriteria) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(CASEINSENSITIVEUSERLIST);
		}
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		String orderBY = searchCriteria.getOrderBy();
		if (orderBY != null) {
			if (searchCriteria.isAsc()) {
				criteria.addOrder(Order.asc(orderBY));
			} else {
				criteria.addOrder(Order.desc(orderBY));
			}
		}
		Set<String> keys = searchCriteria.getAttributeNames();
		Iterator<String> it = keys.iterator();
		String key = null;
		Object value = null;
		while (it.hasNext()) {
			key = it.next();
			value = searchCriteria.getAttribute(key);
			if(value instanceof String)
				criteria.add(Restrictions.ilike(key, value.toString(), MatchMode.START));
			else
				criteria.add(Restrictions.eq(key, value));				
		}
		Transaction transaction = session.beginTransaction();
		List<User> list;
		try {
			list = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return list;
	}

	/**
	 * Gets the case insensitive list of search.
	 *
	 * @param searchCriteria
	 *            the search criteria
	 *
	 * @return the case insensitive list of search
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static List<User> getCaseInsensitiveListOfSearch(
			SearchCriteria searchCriteria) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(CASEINSENSITIVEUSERLIST);
		}
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		criteria.createAlias(AttributeConstants.STATE, AttributeConstants.STATE);
		String orderBY = searchCriteria.getOrderBy();
		if (orderBY != null) {
			if (searchCriteria.isAsc()) {
				criteria.addOrder(Order.asc(orderBY));
			} else {
				criteria.addOrder(Order.desc(orderBY));
			}
		}
		Set<String> keys = searchCriteria.getAttributeNames();
		Iterator<String> it = keys.iterator();
		String key = null;
		Object value = null;
		while (it.hasNext()) {
			key = it.next();
			value = searchCriteria.getAttribute(key);
			if(value instanceof String){
				criteria.add(Restrictions.ilike(key, value.toString(), MatchMode.ANYWHERE));
			} else{
				criteria.add(Restrictions.eq(key, value));
			}
		}
		
		if(searchCriteria.getBalanceFrom() !=null && searchCriteria.getBalanceTo()!=null){
			criteria.add(Restrictions.between("currentBalance", searchCriteria.getBalanceFrom(), searchCriteria.getBalanceTo()));
		}
		Transaction transaction = session.beginTransaction();
		List<User> list;
		try {
			list = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return list;
	}

	/**
	 * Insert user.
	 *
	 * @param user
	 *            the user
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static void insertUser(User user) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Called insertUser method".intern());
		}
		Session session = HibernateUtil.getSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			session.save(user);
			tx.commit();
		} catch (RuntimeException e) {
			log.error("Got exception when insert user with search criteria"
					.intern());
			if (tx != null)
				tx.rollback();
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Update user.
	 *
	 * @param user
	 *            the user
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static void updateUser(User user) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info("Called updateUser method".intern());
		}
		Session session = HibernateUtil.getSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			session.update(user);
			tx.commit();
		} catch (RuntimeException e) {
			log.error("Got exception when update user with search criteria"
					.intern());
			if (tx != null)
				tx.rollback();
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			if(session != null && session.isOpen()){
				session.flush();
				session.close();
			}
		}
	}


	/**
	 * Update user active status.
	 *
	 * @param user the user
	 *
	 * @throws HibernateException the hibernate exception
	 */
	public static void updateUserActive(User user) throws HibernateException {
		if(log.isInfoEnabled()){
			log.info("Called updateUser method".intern());
		}
		Session session = HibernateUtil.getSession();
		Transaction tx = null;
		try {
			tx = session.beginTransaction();
			session.createQuery("update User set active = :active where id = :id".intern()).setBoolean( "active".intern(), user.getActive() ).setInteger( "id".intern(), user.getId()).executeUpdate();
			tx.commit();
		} catch (RuntimeException e) {
			log.error("Got exception when update user with search criteria".intern());
			if (tx != null)
				tx.rollback();
			throw e;
		} finally {
			if(log.isInfoEnabled()){
				log.info(CLOSING_SESSION);
			}
			session.flush();
			session.close();
		}
	}

	/**
	 * Gets the user count.
	 *
	 * @param searchCriteria
	 *            the search criteria
	 *
	 * @return the user count
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static int getUserCount(SearchCriteria searchCriteria)
			throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERACCOUNTSCOUNT);
		}
		if (searchCriteria == null)
			searchCriteria = new SearchCriteria();
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		Set<String> keys = searchCriteria.getAttributeNames();
		Iterator<String> it = keys.iterator();
		String key = null;
		Object value = null;
		if (it.hasNext()) {
			key = it.next();
			value = searchCriteria.getAttribute(key);
		}
		if (value != null) {
			criteria.add(Restrictions.eq(key, value));
			criteria.setProjection(Projections.count(key.toString()));
		} else
			criteria.setProjection(Projections.rowCount());
		Transaction transaction = session.beginTransaction();
		List list;
		try {
			list = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTSEARCHCRITERIAEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		if (list.size() > 0)
			return (Integer) list.get(0);
		else
			return 0;
	}

	/**
	 * Gets the user.
	 *
	 * @param userId
	 *            the user id
	 *
	 * @return the user
	 *
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static User getUser(int userId) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSEARCHCRITERIA);
		}

		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.eq(ID, userId));
		Transaction transaction = session.beginTransaction();
		List<User> userList;
		try {
			userList = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTSEARCHCRITERIAEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return (userList.size() == 0) ? new User() : userList.get(0);
	}

	/**
	 * Gets the registered user list after this date.
	 *
	 * @param date
	 *            the date
	 *
	 * @return the registered user list after this date
	 */
	public static List<UserDateCount> getRegisteredUserListAfterThisDate(Date date) {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSEARCHCRITERIA);
		}
		try {
			date = DateUtil.getDate(DateUtil.getDate(date));
		} catch (Exception e1) {
			e1.printStackTrace();
		}
		Session session = HibernateUtil.getSession();
		Transaction transaction = session.beginTransaction();
		/*Criteria crit = session.createCriteria(User.class);
		ProjectionList projectionList = Projections.projectionList();
		projectionList.add(Projections.count(CREATEDDATE));
		projectionList.add(Projections.property(CREATEDDATE));

		crit.setProjection(projectionList);
		crit.add(Restrictions.ge(CREATEDDATE, date));
		crit.addOrder(Order.asc(CREATEDDATE));*/

		List<?> list = null;
		try {
			list = session.createSQLQuery("select count(createdDate),createdDate from user where createdDate > "+"?"+" group by date_FORMAT(createdDate, '%m %d %Y')".intern()).setDate(0, date).list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		int i = 1;
		List<UserDateCount> list2 = new ArrayList<UserDateCount>();
		for (Iterator<?> iterator = list.iterator(); iterator.hasNext();) {
			UserDateCount userDateCount = new UserDateCount();
			Object[] objects = (Object[]) iterator.next();
			userDateCount.setCount(((BigInteger) objects[0]).intValue());
			userDateCount.setDate((Date) objects[1]);
			userDateCount.setId(i);
			i++;
			list2.add(userDateCount);
		}
		return list2;
	}

	/**
	 * The main method.
	 *
	 * @param userId
	 *            the user id
	 *
	 * @return the user by user id
	 *
	 * @throws Exception
	 *             the exception
	 * @throws HibernateException
	 *             the hibernate exception
	 */
	public static User getUserByUserId(String userId) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSEARCHCRITERIA);
		}

		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.eq(AttributeConstants.USER_ID, userId));
		Transaction transaction = session.beginTransaction();
		List<User> userList;
		try {
			userList = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTSEARCHCRITERIAEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return (userList.size() > 0) ? userList.get(0) : null;
	}


	/**
	 * Gets the user by email.
	 *
	 * @param email the email
	 *
	 * @return the user by email
	 *
	 * @throws HibernateException the hibernate exception
	 */

	public static User getUserByEmail(String email) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSEARCHCRITERIA);
		}
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(User.class);
		criteria.add(Restrictions.eq(AttributeConstants.EMAIL, email));
		Transaction transaction = session.beginTransaction();
		List<User> userList;
		try {
			userList = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTSEARCHCRITERIAEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return (userList.size() == 0) ? null : userList.get(0);
	}

	public static int getTimeZoneId(String countryCode) throws HibernateException {
		if (log.isInfoEnabled()) {
			log.info(USERLISTSEARCHCRITERIA);
		}
		Session session = HibernateUtil.getSession();
		Criteria criteria = session.createCriteria(Timezones.class);
		criteria.add(Restrictions.eq("countryCode", countryCode));
		Transaction transaction = session.beginTransaction();
		List<Timezones> timezonesList;
		try {
			timezonesList = criteria.list();
			transaction.commit();
		} catch (HibernateException e) {
			log.error(USERLISTSEARCHCRITERIAEXCEPTION);
			throw e;
		} finally {
			if (log.isInfoEnabled()) {
				log.info(CLOSING_SESSION);
			}
			session.flush();
			HibernateUtil.closeSession();
		}
		return (timezonesList.size() == 0) ? null : timezonesList.get(0).getId();
	}

	public static void main(String[] args) {
		SearchCriteria criteria = new SearchCriteria();
		criteria.setAttribute("email", "nishan.nn1@ccc.com");
		List l = UserServiceDelegator.getList(criteria);
		CommonFunctionDelegator.GeneralDelete(l.get(0));
	}

	public User createTempuser(){
		User user = new User();
		user.setEmail("temp@temp.com");
		CommonFunctionDelegator.generalInsertbyobj(user);
		return user;
	}
}
